﻿using System;
using System.Diagnostics;

namespace StemServiceWebRole
{
    /// <summary>
    /// Provides various operations related to STEM123 application.
    /// </summary>
    public class StemService : IStemService
    {
        /// <summary>
        /// Initializes a new instance of StemService.
        /// </summary>
        public StemService()
        {
            dbHandler = new DatabaseHandler();
            cloudHandler = new CloudHandler();
        }

        /// <summary>
        /// Publishes metadata related to a publisher and term.
        /// </summary>
        /// <param name="publisher">Name of publisher.</param>
        /// <param name="term">Term of presentation.</param>
        /// <returns>Id of presentation, which is greater than zero else exception.</returns>
        public uint PublishMetadata(string publisher, string term)
        {
            uint presentationId = uint.MinValue;

            // validate input
            if (string.IsNullOrEmpty(publisher) || string.IsNullOrEmpty(term))
            {
                throw new ArgumentNullException("Either publisher or term is null. Please specify both.");
            }

            // log input
            Trace.WriteLine(DateTime.Now.ToString() + " PublishMetadata: Publisher - " + publisher + " Term - " + term);

            // call db to retrieve presentation id
            presentationId = dbHandler.PublishMetadata(publisher, term);

            return presentationId;
        }

        /// <summary>
        /// Uploads content related a presentation.
        /// </summary>
        /// <param name="presentationId">Id of presentation.</param>
        /// <param name="contentType">Type of content.</param>
        /// <param name="content">Array of bytes representing actual content.</param>
        /// <returns>Uri of uploaded content in the cloud.</returns>
        public Uri UploadContent(uint presentationId, ContentTypes contentType, byte[] content)
        {
            // validate input
            if (presentationId <= uint.MinValue)
            {
                throw new ArgumentException("PresentationId is invalid.");
            }
            else if (content == null)
            {
                throw new ArgumentNullException("Content is null.");
            }

            // log input
            Trace.WriteLine(DateTime.Now.ToString() + " UploadContent: PresentationId - " + presentationId + " ContentType - " + contentType);

            // retrieve current version of presentation from db
            uint currentVersion = dbHandler.GetVersion(presentationId);

            // add content for new version and retrieve its URI
            return cloudHandler.AddContent(presentationId, contentType, content, currentVersion + 1); ;
        }

        /// <summary>
        /// Completes publishing of content after publishing metadata and uploading of content.
        /// </summary>
        /// <param name="presentationId">Id of presentation.</param>
        /// <param name="slides">Slides of presentation.</param>
        public void PublishContent(uint presentationId, Slide[] contents)
        {
            // validate input
            if (presentationId <= uint.MinValue)
            {
                throw new ArgumentException("PresentationId is invalid.");
            }
            else if (contents == null)
            {
                throw new ArgumentNullException("No slides information is passed.");
            }
            else if (contents.Length > 3)
            {
                throw new ArgumentException("Number of slides exceeds maximum limit, i.e. 3.");
            }

            // log input
            Trace.WriteLine(DateTime.Now.ToString() + " PublishContent: PresentationId - " + presentationId);

            // call db to store the data for presentation and retrieve latest version
            uint currentVersion = dbHandler.PublishContent(presentationId, contents);

            // call cloud to remove previous version
            if (currentVersion - 1 > uint.MinValue)
            {
                cloudHandler.RemoveContent(presentationId, currentVersion - 1);
            }
        }

        /// <summary>
        /// Searches for presentations related to a term (and publisher).
        /// </summary>
        /// <param name="publisher">Name of publisher (optional).</param>
        /// <param name="term">Term to be searched.</param>
        /// <returns>Results of search.</returns>
        public SearchResults Search(string publisher, string term)
        {
            // validate input
            if (string.IsNullOrEmpty(term))
            {
                throw new ArgumentNullException("No term was specified in search.");
            }

            // log input
            Trace.WriteLine(DateTime.Now.ToString() + " Search: Publisher - " + publisher + " Term - " + term);

            // call db to perform search and retrieve results
            return dbHandler.Search(publisher, term);
        }

        /// <summary>
        /// Interacts with SQL Azure storage.
        /// </summary>
        private DatabaseHandler dbHandler;

        /// <summary>
        /// Interacts with Windows Azure storage.
        /// </summary>
        private CloudHandler cloudHandler;
    }
}